package com.qijian.production.service.impl;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qijian.common.exception.ServiceException;
import com.qijian.common.utils.DateUtils;
import com.qijian.common.utils.DatesUtil;
import com.qijian.common.utils.SecurityUtils;
import com.qijian.common.utils.StringUtils;
import com.qijian.common.utils.bean.BeanUtils;
import com.qijian.common.utils.mybatis.WhereEntityTool;
import com.qijian.common.utils.mybatis.WhereType;
import com.qijian.common.utils.uuid.IdUtils;
import com.qijian.maindata.domain.*;
import com.qijian.maindata.domain.query.*;
import com.qijian.maindata.domain.vo.BomDetailAllVo;
import com.qijian.maindata.domain.vo.InspectionItemDetailVo;
import com.qijian.maindata.service.*;
import com.qijian.production.domain.ScWorkOrder;
import com.qijian.production.domain.ScWorkOrderCraftItem;
import com.qijian.production.domain.ScWorkOrderDetail;
import com.qijian.production.domain.query.ScWorkOrderDetailQuery;
import com.qijian.production.domain.query.ScWorkOrderQuery;
import com.qijian.production.domain.vo.ScWorkOrderDetailVo;
import com.qijian.production.domain.vo.ScWorkOrderVo;
import com.qijian.production.domain.vo.WorkOrderExcelVo;
import com.qijian.production.mapper.ScWorkOrderDetailMapper;
import com.qijian.production.mapper.ScWorkOrderMapper;
import com.qijian.production.service.IScWorkOrderCraftItemService;
import com.qijian.production.service.IScWorkOrderDetailService;
import com.qijian.production.service.IScWorkOrderService;
import org.springframework.beans.factory.annotation.Autowired;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;

/**
 * 生产计划单Service业务层处理
 *
 * @author zhangcheng
 * @date 2025-03-25
 */
@Service
@RequiredArgsConstructor
public class ScWorkOrderServiceImpl extends ServiceImpl<ScWorkOrderMapper, ScWorkOrder> implements IScWorkOrderService {

    private final ScWorkOrderMapper workOrderMapper;
    private final IScWorkOrderDetailService workOrderDetailService;
    private final ScWorkOrderDetailMapper workOrderDetailMapper;
    private final IScWorkOrderCraftItemService workOrderCraftItemService;
    private final IItemService itemService;
    private final IBomService bomService;
    private final IBomDetailService bomDetailService;
    private final ILineProcessService lineProcessService;
    private final ILineProcessItemService lineProcessItemService;
    private final ILineService lineService;
    private final ILineProcessSchemeService lineProcessSchemeService;
    private final ILineProcessWorkService lineProcessWorkService;

    @Override
    public Page<ScWorkOrderVo> pageVo(Page<ScWorkOrder> page, QueryWrapper<ScWorkOrderQuery> query) {

        return workOrderMapper.pageVo(page, query);
    }

    @Override
    public Page<ScWorkOrderVo> pageDetailVo(Page<ScWorkOrder> page, QueryWrapper<ScWorkOrderQuery> query) {
        return workOrderMapper.pageDetailVo(page, query);
    }

    @Override
    public List<ScWorkOrderVo> listDetailForProduction(ScWorkOrderDetailQuery query) {
        List<ScWorkOrderVo> workOrderVoList = new ArrayList<>();
        query.setIsToday(true);
        List<ScWorkOrderDetailVo> workOrderDetailList = listDetail(WhereEntityTool.invoke(query));
        if (workOrderDetailList.isEmpty()) return new ArrayList<>();
        // 根据订单为工序分组
        Map<Long, List<ScWorkOrderDetailVo>> workOrderMap = workOrderDetailList.stream().collect(Collectors.groupingBy(ScWorkOrderDetailVo::getWorkOrderId));
        workOrderMap.forEach((key, value) -> {
            ScWorkOrderDetailQuery workOrderDetailQuery = new ScWorkOrderDetailQuery();
            workOrderDetailQuery.setWorkOrderId(key);
            // 获取计划单所有工序
            List<ScWorkOrderDetail> allProcessList = workOrderDetailService.list(WhereEntityTool.invoke(workOrderDetailQuery)).stream().sorted(Comparator.comparing(ScWorkOrderDetail::getSort)).collect(Collectors.toList());
            value.forEach(item -> {
                ScWorkOrderVo workOrderVo = new ScWorkOrderVo();
                BeanUtils.copyProperties(item, workOrderVo);
                workOrderVo.setId(item.getWorkOrderId());
                // 默认返回前后一共三道工序
                List<String> bfList = new LinkedList<>();
                int size = allProcessList.size();
                for (int i = 0; i < size; i++) {
                    ScWorkOrderDetail current = allProcessList.get(i);
                    if (item.getSort() != current.getSort()) continue;
                    if (i == 0) {
                        addSafely(bfList, allProcessList, i);
                        addSafely(bfList, allProcessList, i + 1);
                        addSafely(bfList, allProcessList, i + 2);
                    } else if (i == size - 1) {
                        addSafely(bfList, allProcessList, i - 2);
                        addSafely(bfList, allProcessList, i - 1);
                        addSafely(bfList, allProcessList, i);
                    } else {
                        addSafely(bfList, allProcessList, i - 1);
                        addSafely(bfList, allProcessList, i);
                        addSafely(bfList, allProcessList, i + 1);
                    }
                }
                workOrderVo.setAllProcess(bfList);
                BigDecimal completionRate = item.getProducedQty().divide(item.getQty(), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
                completionRate = completionRate.compareTo(new BigDecimal(100)) > 0 ? new BigDecimal(100) : completionRate;
                workOrderVo.setCompletionRate(completionRate);
                workOrderVoList.add(workOrderVo);
            });
        });
        return workOrderVoList;
    }

    @Override
    public ScWorkOrderVo getOrderDetailDataByQuery(ScWorkOrderQuery query) {
        return baseMapper.getOrderDetailByQuery(WhereEntityTool.invoke(query));
    }

    @Override
    public List<ScWorkOrderVo> getChildWorkOrder(Long workOrderId) {
        return baseMapper.geChildWorkOrder(workOrderId);
    }

    @Override
    public List<ScWorkOrderVo> getNeedItem(Long workOrderId, Long workOrderDetailId) {
        return baseMapper.getNeedItem(workOrderId, workOrderDetailId);
    }


    /**
     * 导入生产计划单
     * @param list
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean importWorkOrder(List<WorkOrderExcelVo> list) {
        validateExcelData(list);
        List<ScWorkOrder> workOrderList = preWorkOrder(list);
        List<ScWorkOrder> allWorkOrder = matchBom(workOrderList);
        createCraft(allWorkOrder);
        return saveBatch(allWorkOrder);
    }

    @Override
    public ScWorkOrderVo getMaxSortData(Long workOrderId) {
        return baseMapper.getMaxSortData(workOrderId);
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean split(Set<Long> ids) {
        ScWorkOrderQuery workOrderQuery = new ScWorkOrderQuery();
        workOrderQuery.setIds(ids);
        List<ScWorkOrder> workOrderList = list(WhereEntityTool.invoke(workOrderQuery));
        for (ScWorkOrder workOrder : workOrderList) {
            if (workOrder.getIsProcess()) {
                throw new ServiceException("计划单【" + workOrder.getOrderNo() + "】已存在生产工单！");
            }
            if (StringUtils.isNotNull(workOrder.getParentId())) {
                throw new ServiceException("计划单错误！");
            }
        }
        List<ScWorkOrder> allWorkOrder = matchBom(workOrderList);
        createCraft(allWorkOrder);
        return saveOrUpdateBatch(allWorkOrder);
    }

    @Override
    public ScWorkOrderDetailVo getReportingData(Long detailId) {
        ScWorkOrderDetailVo workOrderDetailVo = workOrderMapper.selectWorkOrderDetailByDetailId(detailId);
        // 获取质检方案
        List<InspectionItemDetailVo> inspectionItemDetailList = lineProcessSchemeService.selectInspectionItemDetail(workOrderDetailVo.getLineProcessId());
        workOrderDetailVo.setInspectionItemDetailList(inspectionItemDetailList);
        return workOrderDetailVo;
    }

    @Override
    public List<ScWorkOrderDetailVo> listDetail(QueryWrapper<ScWorkOrderDetailQuery> query) {
        Page<ScWorkOrderDetailVo> scWorkOrderDetailVoPage = workOrderMapper.listDetail(Page.of(1, -1), query);
        for (ScWorkOrderDetailVo record : scWorkOrderDetailVoPage.getRecords()) {
            BigDecimal completionRate = record.getProducedQty().divide(record.getQty(), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            completionRate = completionRate.compareTo(new BigDecimal(100)) > 0 ? new BigDecimal(100) : completionRate;
            record.setCompletionRate(completionRate);
        }
        return scWorkOrderDetailVoPage.getRecords();
    }

    @Override
    public Page<ScWorkOrderDetailVo> pageDetail(Page<ScWorkOrderDetail> page, QueryWrapper<ScWorkOrderDetailQuery> query) {
        Page<ScWorkOrderDetailVo> scWorkOrderDetailVoPage = workOrderMapper.listDetail(page, query);
        for (ScWorkOrderDetailVo record : scWorkOrderDetailVoPage.getRecords()) {
            BigDecimal completionRate = record.getProducedQty().divide(record.getQty(), 2, RoundingMode.HALF_UP).multiply(new BigDecimal(100));
            completionRate = completionRate.compareTo(new BigDecimal(100)) > 0 ? new BigDecimal(100) : completionRate;
            record.setCompletionRate(completionRate);
        }
        return scWorkOrderDetailVoPage;
    }

    @Override
    public ScWorkOrderVo getPassRateReportHead(ScWorkOrderQuery scWorkOrderQuery) {
        Date[] planStartDate = scWorkOrderQuery.getPlanStartDate();
        if (planStartDate == null) {
            planStartDate = new Date[2];
            planStartDate[0] = DatesUtil.getDayBegin();
            planStartDate[1] = DatesUtil.getDayEnd();
            scWorkOrderQuery.setPlanStartDate(planStartDate);
        }
        scWorkOrderQuery.setUserId(SecurityUtils.getUserId());
        ScWorkOrderVo passRateReportHead = baseMapper.getPassRateReportHead(WhereEntityTool.invoke(scWorkOrderQuery));
        BigDecimal sumBadNumber = passRateReportHead.getSumBadNumber();
        BigDecimal sumFinishQty = passRateReportHead.getSumFinishQty();
        passRateReportHead.setMonthProducedQty(sumFinishQty.add(sumBadNumber));
        return passRateReportHead;
    }

    @Override
    public Page<ScWorkOrderVo> getPassRateReportBody(Page<ScWorkOrder> page, ScWorkOrderQuery scWorkOrderQuery) {
        Date[] planStartDate = scWorkOrderQuery.getPlanStartDate();
        if (planStartDate == null) {
            planStartDate = new Date[2];
            planStartDate[0] = DatesUtil.getDayBegin();
            planStartDate[1] = DatesUtil.getDayEnd();
            scWorkOrderQuery.setPlanStartDate(planStartDate);
        }
        scWorkOrderQuery.setUserId(SecurityUtils.getUserId());
        return baseMapper.getPassRateReportBody(page, WhereEntityTool.invoke(scWorkOrderQuery));
    }

    @Override
    public Boolean startWork(Long id) {
        ScWorkOrderDetail workOrderDetail = new ScWorkOrderDetail();
        workOrderDetail.setId(id);
        workOrderDetail.setStatus("生产中");
        workOrderDetail.setStartDate(new Date());
        return workOrderDetailService.updateById(workOrderDetail);
    }

    @Override
    public Boolean workOver(Long id) {
        ScWorkOrderDetail workOrderDetail = new ScWorkOrderDetail();
        workOrderDetail.setId(id);
        workOrderDetail.setStatus("已完成");
        workOrderDetail.setEndDate(new Date());
        return workOrderDetailService.updateById(workOrderDetail);
    }

    private void addSafely(List<String> target, List<ScWorkOrderDetail> source, int index) {
        if (index >= 0 && index < source.size()) {
            target.add(source.get(index).getProcessName());
        }
    }

    /**
     * 校验excel数据
     * @param list
     */
    private void validateExcelData(List<WorkOrderExcelVo> list) {
        list = list.stream().filter(StringUtils::isNotNull).collect(Collectors.toList());
        for (WorkOrderExcelVo workOrderExcelVo : list) {
            if (StringUtils.isEmpty(workOrderExcelVo.getOrderNo())) {
                throw new RuntimeException("订单号不能为空");
            }
            if (StringUtils.isEmpty(workOrderExcelVo.getItemCode())) {
                throw new RuntimeException("物料号不能为空");
            }
            ItemQuery itemQuery = new ItemQuery();
            itemQuery.setItemCodeEq(workOrderExcelVo.getItemCode());
            if (StringUtils.isNull(itemService.getOne(WhereEntityTool.invoke(itemQuery)))) {
                throw new RuntimeException("物料号【" + workOrderExcelVo.getItemCode() + "】不存在");
            }
            if (StringUtils.isNull(workOrderExcelVo.getQty())) {
                throw new RuntimeException("订单数量不能为空");
            }
        }
    }

    /**
     * 预处理数据
     * @param list
     * @return
     */
    private List<ScWorkOrder> preWorkOrder(List<WorkOrderExcelVo> list) {
        Map<String, List<WorkOrderExcelVo>> orderNoMap = list.stream().collect(Collectors.groupingBy(WorkOrderExcelVo::getOrderNo));
        List<ScWorkOrder> dbWorkOrderList = list();
        List<Long> delIds = new ArrayList<>();
        for (ScWorkOrder workOrder : dbWorkOrderList) {
            if (orderNoMap.containsKey(workOrder.getOrderNo()) && workOrder.getStatus().equals("0")) {
                // 如果订单号相同，并且状态为待排产，则删除该订单
                delIds.add(workOrder.getId());
            }
        }
        if (StringUtils.isNotEmpty(delIds)) {
            removeByIds(delIds);
            workOrderDetailService.remove(new LambdaQueryWrapper<ScWorkOrderDetail>().in(ScWorkOrderDetail::getWorkOrderId, delIds));
            workOrderCraftItemService.remove(new LambdaQueryWrapper<ScWorkOrderCraftItem>().in(ScWorkOrderCraftItem::getOrderId, delIds));
        }
        if (StringUtils.isNotEmpty(dbWorkOrderList)) {
            List<String> orderNoList = dbWorkOrderList.stream().map(ScWorkOrder::getOrderNo).distinct().collect(Collectors.toList());
            list = list.stream().filter(e -> !orderNoList.contains(e.getOrderNo())).collect(Collectors.toList());
        }
        List<ScWorkOrder> workOrderList = new ArrayList<>();
        for (WorkOrderExcelVo workOrderExcelVo : list) {
            ScWorkOrder scWorkOrder = new ScWorkOrder();
            BeanUtils.copyProperties(workOrderExcelVo, scWorkOrder);
            workOrderList.add(scWorkOrder);
        }
        return workOrderList;
    }

    /**
     * 匹配计划单物料BOM
     * @param workOrderList
     * @return
     */
    private List<ScWorkOrder> matchBom(List<ScWorkOrder> workOrderList) {
        List<ScWorkOrder> allWorkOrderList = new ArrayList<>();
        for (ScWorkOrder workOrder : workOrderList) {
            // 查询产品匹配的BOM
            BomQuery bomQuery = new BomQuery();
            bomQuery.setItemCode(workOrder.getItemCode());
            List<Bom> bomList = bomService.list(WhereEntityTool.invoke(bomQuery));
            Bom bom;
            if (StringUtils.isEmpty(bomList)) {
                if (StringUtils.isNull(workOrder.getId())) {
                    workOrder.setId(IdUtils.singletonSnowId());
                }
                workOrder.setIsProcess(false);
                workOrder.setProportion(BigDecimal.valueOf(1));
                workOrder.setTopOrderId(workOrder.getId());
                workOrder.setAncestors(String.valueOf(workOrder.getId()));
                allWorkOrderList.add(workOrder);
                continue;
            } else {
                bom = bomList.get(bomList.size() - 1);
            }
            BomDetailQuery query = new BomDetailQuery();
            query.setBomId(bom.getBomId());
            List<BomDetailAllVo> bomDetailAllVos = bomDetailService.selectAllVo(WhereEntityTool.invoke(query));
            if (StringUtils.isNotEmpty(bomDetailAllVos) && StringUtils.isNull(bomDetailAllVos.get(0).getLineId())) {
                // 产品还未绑定工艺路线则先不展开bom
                if (StringUtils.isNull(workOrder.getId())) {
                    workOrder.setId(IdUtils.singletonSnowId());
                }
                workOrder.setIsProcess(false);
                workOrder.setProportion(BigDecimal.valueOf(1));
                workOrder.setTopOrderId(workOrder.getId());
                workOrder.setAncestors(String.valueOf(workOrder.getId()));
                allWorkOrderList.add(workOrder);
                continue;
            }
            List<ScWorkOrder> flatList = flatBom(bomDetailAllVos, workOrder, new HashMap<>()).stream().sorted(Comparator.comparing(ScWorkOrder::getSort)).collect(Collectors.toList());
            for (ScWorkOrder order : flatList) {

            }
            allWorkOrderList.addAll(flatList);
        }
        return allWorkOrderList;
    }

    /**
     * 展开BOM
     * @param bomDetailAllVos
     * @param workOrder
     * @param idMap
     * @return
     */
    private List<ScWorkOrder> flatBom(List<BomDetailAllVo> bomDetailAllVos, ScWorkOrder workOrder, Map<Long, Long> idMap) {
        Map<Long, ScWorkOrder> workOrderIdMap = new HashMap<>();
        Map<String, Long> detailCodeIdMap = new HashMap<>();
        Long topId = null;
        int sort = 1;
        for (BomDetailAllVo bomDetailAllVo : bomDetailAllVos) {
            if (StringUtils.isNotNull(bomDetailAllVo.getLineId())) {
                ScWorkOrder _workOrder = new ScWorkOrder();
                BeanUtils.copyBeanProp(_workOrder, bomDetailAllVo);
                Long id = IdUtils.singletonSnowId();
                if (StringUtils.isNotNull(idMap) && idMap.containsKey(bomDetailAllVo.getDetailId())) {
                    _workOrder.setId(idMap.get(bomDetailAllVo.getDetailId()));
                } else {
                    _workOrder.setId(id);
                }
                _workOrder.setOrderNo(workOrder.getOrderNo());
                _workOrder.setFactoryCode(workOrder.getFactoryCode());
                _workOrder.setPlanStartDate(workOrder.getPlanStartDate());
                _workOrder.setPlanEndDate(workOrder.getPlanEndDate());
                _workOrder.setActualStartDate(workOrder.getActualStartDate());
                _workOrder.setActualEndDate(workOrder.getActualEndDate());
                _workOrder.setDeliverDate(workOrder.getDeliverDate());
                _workOrder.setMainBomDetailId(bomDetailAllVo.getDetailId());
                _workOrder.setIsProcess(true);
                _workOrder.setLineId(bomDetailAllVo.getLineId());
                _workOrder.setItemId(bomDetailAllVo.getItemId());
                _workOrder.setItemCode(bomDetailAllVo.getItemCode());
                _workOrder.setItemName(bomDetailAllVo.getItemName());
                _workOrder.setDetailCode(bomDetailAllVo.getDetailCode());
                BigDecimal totalQuantity = bomDetailAllVo.getTotalQuantity();
                if (sort != 1) {
                    totalQuantity = extracted(bomDetailAllVo.getDetailId(), bomDetailAllVos);
                }
                _workOrder.setOldQty(workOrder.getQty().multiply(totalQuantity));
                _workOrder.setQty(_workOrder.getOldQty());
                _workOrder.setProportion(totalQuantity);
                _workOrder.setIsContain(false);
                if (bomDetailAllVo.getLevel() == 0) {
                    _workOrder.setParentId(null);
                    _workOrder.setProductType(workOrder.getProductType());
                    // 2024.11.20 宏泽需求对已有计划单（拆分）操作的时候，保留原有计划单的id和number
                    if (StringUtils.isNotNull(workOrder.getId())) {
                        _workOrder.setId(workOrder.getId());
                    }
                    if (StringUtils.isNotEmpty(workOrder.getNumber())) {
                        _workOrder.setNumber(workOrder.getNumber());
                    }
                    topId = _workOrder.getId();
                } else if (bomDetailAllVo.getLevel() == 1) {
                    workOrderIdMap.get(detailCodeIdMap.get("0")).setIsContain(true);
                    _workOrder.setParentId(detailCodeIdMap.get("0"));
                } else {
                    Long pid = detailCodeIdMap.get(bomDetailAllVo.getDetailCode().substring(0, bomDetailAllVo.getDetailCode().lastIndexOf(".")));
                    if (StringUtils.isNull(pid)) {
                        throw new ServiceException("BOM【" + bomDetailAllVos.get(0).getItemCode() + "】存在节点上级没有配置工艺线路");
                    }
                    workOrderIdMap.get(pid).setIsContain(true);
                    _workOrder.setParentId(pid);
                }
                _workOrder.setBomId(bomDetailAllVo.getBomId());
                _workOrder.setSort(sort++);
                _workOrder.setTopOrderId(topId);
                String s = createAncestors(workOrderIdMap, _workOrder.getParentId(), String.valueOf(_workOrder.getId()));
                _workOrder.setAncestors(s);
                workOrderIdMap.put(_workOrder.getId(), _workOrder);
                detailCodeIdMap.put(bomDetailAllVo.getDetailCode(), _workOrder.getId());
            }
        }
        return new ArrayList<>(workOrderIdMap.values());
    }


    /**
     * 创建生产计划单工序
     * @param allWorkOrderList
     */
    public void createCraft(List<ScWorkOrder> allWorkOrderList) {
        List<ScWorkOrderDetailVo> workOrderDetailVoList = new ArrayList<>();
        for (ScWorkOrder workOrder : allWorkOrderList) {
            ScWorkOrderDetailVo vo = new ScWorkOrderDetailVo();
            vo.setWorkOrderId(workOrder.getId());
            List<ScWorkOrderDetail> workOrderDetailList = new ArrayList<>();
            LineProcessQuery lineProcessQuery = new LineProcessQuery();
            lineProcessQuery.setLineId(workOrder.getLineId());
            List<LineProcess> lineList = lineProcessService.list(WhereEntityTool.invoke(lineProcessQuery)).stream().sorted(Comparator.comparing(LineProcess::getSort)).toList();
            if (StringUtils.isNotNull(workOrder.getLineId()) && workOrder.getLineId() != 0 && StringUtils.isEmpty(lineList)) {
                Line line = lineService.getById(workOrder.getLineId());
                throw new ServiceException("工艺线路【" + line.getLineCode() + "】未配置工序");
            }
            for (LineProcess lineProcess : lineList) {
                ScWorkOrderDetail workOrderDetail = new ScWorkOrderDetail();
                workOrderDetail.setOrderNo(workOrder.getOrderNo());
                workOrderDetail.setWorkOrderId(workOrder.getId());
                workOrderDetail.setSort(lineProcess.getSort());
                workOrderDetail.setLineProcessId(lineProcess.getProcessId());
                workOrderDetail.setProcessId(lineProcess.getPid());
                workOrderDetail.setProcessCode(lineProcess.getProcessCode());
//                workOrderDetail.setQty(workOrder.getQty());
                BigDecimal totalProportion = calCraftProportion(lineProcess, lineList);
                workOrderDetail.setQty(workOrder.getQty().multiply(totalProportion));
                workOrderDetail.setProportion(lineProcess.getProportion());
                workOrderDetail.setProcessName(lineProcess.getProcessName());
                // 生产位置
                LineProcessWorkQuery lineProcessWorkQuery = new LineProcessWorkQuery();
                lineProcessWorkQuery.setProcessId(lineProcess.getProcessId());
                List<LineProcessWork> lineProcessWorkList = lineProcessWorkService.list(WhereEntityTool.invoke(lineProcessWorkQuery));
                if (StringUtils.isNotNull(lineProcessWorkList)) {
                    workOrderDetail.setLocationId(lineProcessWorkList.get(0).getFactoryId());
                    workOrderDetail.setLocation(lineProcessWorkList.get(0).getFactoryName());
                }

                // 物料需求
                LineProcessItemQuery lineProcessItemQuery = new LineProcessItemQuery();
                lineProcessItemQuery.setProcessId(lineProcess.getProcessId());
                List<LineProcessItem> lineProcessItemList = lineProcessItemService.list(WhereEntityTool.invoke(lineProcessItemQuery));
                List<ScWorkOrderCraftItem> workOrderCraftItemList = new ArrayList<>();
                for (LineProcessItem lineProcessItem : lineProcessItemList) {
                    ScWorkOrderCraftItem workOrderCraftItem = new ScWorkOrderCraftItem();
                    workOrderCraftItem.setItemId(lineProcessItem.getItemId());
                    workOrderCraftItem.setItemCode(lineProcessItem.getItemCode());
                    workOrderCraftItem.setItemName(lineProcessItem.getItemName());
                    workOrderCraftItem.setItemUnits(lineProcessItem.getItemUnits());
                    workOrderCraftItem.setBomId(lineProcessItem.getBomId());
                    workOrderCraftItem.setDemandId(lineProcessItem.getDemandId());
                    workOrderCraftItem.setLineCode(lineProcessItem.getLineCode());
                    workOrderCraftItem.setLineId(lineProcessItem.getLineId());
                    workOrderCraftItem.setLineProcessId(lineProcessItem.getProcessId());
                    workOrderCraftItem.setProcessCode(lineProcess.getProcessCode());
                    workOrderCraftItem.setProcessId(lineProcessItem.getProcessId());
                    workOrderCraftItem.setQty(lineProcessItem.getQuantity());
                    workOrderCraftItemList.add(workOrderCraftItem);
                }
                workOrderDetail.setWorkOrderCraftItemList(workOrderCraftItemList);
                workOrderDetailList.add(workOrderDetail);
            }
            vo.setWorkOrderDetailList(workOrderDetailList);
            workOrderDetailVoList.add(vo);
        }
        addCraft(workOrderDetailVoList);
    }

    private BigDecimal calCraftProportion(LineProcess lineProcess, List<LineProcess> lineList) {
        BigDecimal totalProportion = new BigDecimal(1);
        for (int i = 0; i < lineList.size(); i++) {
            if (lineList.get(i).getSort() > lineProcess.getSort()) {
                totalProportion = totalProportion.multiply(lineList.get(i).getProportion());
            }
        }
        return totalProportion;
    }

    /**
     * 保存生产工序和物料需求
     * @param workOrderDetailVoList
     */
    private void addCraft(List<ScWorkOrderDetailVo> workOrderDetailVoList) {
        List<ScWorkOrderDetail> workOrderDetailList = new ArrayList<>();
        List<ScWorkOrderCraftItem> workOrderCraftItemList = new ArrayList<>();
        int count = workOrderDetailMapper.countCurrentDateWithDel();
        if (count == 0){
            count = 1;
        }
        String pre = "WO" + DateUtil.format(new Date(), "yyyyMMdd");
        for (ScWorkOrderDetailVo workOrderDetailVo : workOrderDetailVoList) {
            if (workOrderDetailVo.getWorkOrderId() == null) {
                throw new ServiceException("工单id为空");
            }
            if (workOrderDetailVo.getWorkOrderDetailList().size() == 0) {
                continue;
            }

            for (ScWorkOrderDetail workOrderDetail : workOrderDetailVo.getWorkOrderDetailList()) {
                Long id = IdUtils.singletonSnowId();
                workOrderDetail.setId(id);
                String format = String.format("%06d", count++);
                workOrderDetail.setDetailNo(pre + format);
                workOrderDetailList.add(workOrderDetail);
                for (ScWorkOrderCraftItem workOrderCraftItem : workOrderDetail.getWorkOrderCraftItemList()) {
                    workOrderCraftItem.setId(IdUtils.singletonSnowId());
                    workOrderCraftItem.setOrderDetailId(id);
                    workOrderCraftItem.setOrderId(workOrderDetail.getWorkOrderId());
                    workOrderCraftItem.setSort(workOrderDetail.getSort());
                    workOrderCraftItemList.add(workOrderCraftItem);
                }
            }
        }
        workOrderDetailService.saveBatch(workOrderDetailList);
        workOrderCraftItemList = workOrderCraftItemList.stream().distinct().collect(Collectors.toList());
        workOrderCraftItemService.saveBatch(workOrderCraftItemList);
    }



    private String createAncestors(Map<Long, ScWorkOrder> workOrderIdMap, Long parentId, String s) {
        ScWorkOrder workOrder = workOrderIdMap.get(parentId);
        if (StringUtils.isNull(workOrder)) {
            return s;
        }

        return createAncestors(workOrderIdMap, workOrder.getParentId(), String.valueOf(workOrder.getId())) + "," + s;
    }

    private BigDecimal extracted(Long detailId, List<BomDetailAllVo> bomDetailAllVos) {
        BigDecimal totalQuantity = BigDecimal.ONE;
        Long detailIds = detailId;
        for (BomDetailAllVo bomDetailAllVo : bomDetailAllVos) {
            BomDetailQuery query = new BomDetailQuery();
            query.setDetailId(detailIds);
            List<BomDetailAllVo> bomDetailAllVos1 = bomDetailService.selectAllVo(WhereEntityTool.invoke(query));
            if (bomDetailAllVos1 != null && bomDetailAllVos1.size() != 0) {
                BomDetailAllVo bomDetailAllVo1 = bomDetailAllVos1.get(0);
                if (bomDetailAllVo1.getLevel() != 0) {
                    totalQuantity = bomDetailAllVo1.getTotalQuantity().multiply(totalQuantity);
                    detailIds = bomDetailAllVo1.getPid();
                } else {
                    break;
                }
            } else {
                break;
            }
        }
        return totalQuantity;
    }

}

